<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="/snake.css">
</head>

<body>
  <script>
    //地图构造函数
    function SnakeMap(xCellNumber = 40, yCellNumber = 30, cellWidth = 20, cellHeight = 20) {
      // 地图横向单元格的数量
      this.xCellNumber = xCellNumber;
      // 地图纵向单元格的数量
      this.yCellNumber = yCellNumber;
      // 单元格的高度
      this.cellHeight = cellHeight;
      // 单元格的宽度
      this.cellWidth = cellWidth;
      // 保存地图的div对象
      this.mapDom = null;
      this.show()
    }
    SnakeMap.prototype.show = function () {
      this.mapDom = document.createElement('div');
      this.mapDom.className = 'map';
      this.mapDom.style.width = this.xCellNumber * this.cellWidth + 'px'
      this.mapDom.style.height = this.yCellNumber * this.cellHeight + 'px'
      document.body.appendChild(this.mapDom)
    }
    // 食物构造函数
    function Food(map) {
      if (!(map instanceof SnakeMap)) {
        throw new Error('传入的参数不是地图对象')
      }
      // 保存食物的位置
      this.x = 0;
      this.y = 0;
      // 接收地图的dom对象
      this.map = map;
      // 保存食物的dom对象
      this.fooDom = null
      this.show()
    }
    // 食物出现的方法
    Food.prototype.show = function () {
      if (!this.fooDom) {
        this.fooDom = document.createElement('div');
        this.fooDom.className = 'food';
        this.map.mapDom.appendChild(this.fooDom);
      }
      this.x = this.makeRandom(0, this.map.xCellNumber);
      this.y = this.makeRandom(0, this.map.yCellNumber);
      this.fooDom.style.left = this.x * this.map.cellWidth + 'px';
      this.fooDom.style.top = this.y * this.map.cellHeight + 'px';
    }
    // 使用箭头函数无须return  普通函数需要返回值 要return
    Food.prototype.makeRandom = function (start, end) {
      // 一共40个格子 所以不包含结束位置
      return Math.floor(Math.random() * (end - start)) + start;
    }
    // 蛇的构造函数
    function Snake(food) {
      if (!(food instanceof Food)) {
        throw new Error('传入的必须是食物的对象')
      }
      this.timer = null;
      // 将食物的对象保存进来
      this.food = food
      // 保存移动方向
      this.direct = 'right';
      // 保存蛇的每一节状态
      this.bodys = [
        { x: 3, y: 0, backgroundImage: 'url(imgs/head.png)', dom: null },
        { x: 2, y: 0, backgroundImage: 'url(imgs/body.png)', dom: null },
        { x: 1, y: 0, backgroundImage: 'url(imgs/body.png)', dom: null }
      ]
      this.show();
      this.start();

    }
    // 蛇出现的方法
    Snake.prototype.show = function () {
      this.bodys.forEach((item, index) => {
        if (!item.dom) {
          item.dom = document.createElement('div')
          item.dom.className = 'snake';
          item.dom.style.backgroundImage = item.backgroundImage
          this.food.map.mapDom.appendChild(item.dom)
        }
        item.dom.style.left = item.x * 20 + 'px'
        item.dom.style.top = item.y * 20 + 'px'
      })
    }
    // 蛇启动的方法
    Snake.prototype.start = function () {
      this.changeRedict();
      this.timer = setInterval(() => {
        this.move();
      }, 300)
    }
    // 判断操作方向
    Snake.prototype.changeRedict = function () {
      window.onkeydown = e => {
        switch (e.keyCode) {
          case 38:
          case 87:
            this.direct = 'up';
            break;
          case 40:
          case 83:
            this.direct = 'down';
            break;
          case 37:
          case 65:
            this.direct = 'left';
            break;
          case 39:
          case 68:
            this.direct = 'right';
            break;
          default:
            alert('按方向键或按wasd进行控制！！！')
            break;
        }
        //console.log(e.keyCode)
      }
    }
    // 蛇移动的方法
    Snake.prototype.move = function () {
      // 因为蛇移动需要以尾为主，避免身体分离。
      // 身体的每一部分都是 前一部分之前的位置 所以对蛇的身体进行反向遍历
      for (let i = this.bodys.length - 1; i > 0; i--) {
        this.bodys[i].x = this.bodys[i - 1].x;
        this.bodys[i].y = this.bodys[i - 1].y;
      }
      //改变蛇尾的位置
      switch (this.direct) {
        case 'right':
          this.bodys[0].x++;
          break;
        case 'left':
          this.bodys[0].x--;
          break;
        case 'up':
          this.bodys[0].y--;
          break;
        case 'down':
          this.bodys[0].y++;
          break;
        default:
          break;
      }
     this.die();
      this.eat();
      this.show()
    }
    // 蛇吃食物 需要在蛇移动的过程中判断是否吃到
    Snake.prototype.eat = function () {
      // 头的位置和食物的位置重合就说明吃到食物
      if (this.bodys[0].x == this.food.x && this.bodys[0].y == this.food.y) {
        // 食物消失 下一个食物出现

        let last = this.bodys[this.bodys.length - 1]
        // 必须重新 添加一节新的进去 以为dom需要设置为null、
        this.bodys.push({
          x: last.x,
          y: last.y,
          backgroundImage: last.backgroundImage,
          dom: null
        })
        this.food.show();
      }
    }
    // 判断蛇是否死亡
    Snake.prototype.die = function () {
      if (this.bodys[0].x <= 0||this.bodys[0].x>=this.food.map.xCellNumber||this.bodys[0].y < 0||this.bodys[0].y>=this.food.map.yCellNumber ) {
        clearInterval(this.timer)
        
        alert('game over!!!')
       
      }
      this.show()
    }
    let map = new SnakeMap()
    // map.show()
    let food = new Food(map)
    //food.show();
    let snake = new Snake(food)
    //snake.changeRedict()
    // snake.show();
  </script>
</body>

</html>